<template>
  <div :id="comId" @layout="comChanges">
    <slot></slot>
  </div>
</template>
<script>
import Vue from "vue";
import { getUUid, getCommentInfo } from "@/hippy-focus/path/utils";
import { queryWidgetByShadowAlgorithm, queryWidgetByAreaAlgorithm } from "@/hippy-focus/path/fecalc";
import { KEYCODE } from "@/utils";
export default {
  name: "focus-switch",
  provide() {
    return {
      focusSwitchState: this.state,
      focusSwitchMethods: {
        widgetChange: this.widgetChange,
        otherComChange: this.otherComChange,
        onChangeFocus: this.onChangeFocus,
      },
      $focusBoxs: this.$box,
      $focusWidgets: this.$widget,
    }
  },
  inject: ["focusFrameMethods"],
  components: {},
  data() {
    return {
      comId: getUUid(),
      state: {
        focusId: null,
      },
    };
  },
  beforeCreate() {
    this.$widget = {};
    this.$components = {};
  },
  created() {

  },
  mounted() {

  },
  computed: {

  },
  beforeDestroy() {
    this.comChanges({}, true)
  },
  methods: {
    onMove(_keycode) {
      let _focusId = queryWidgetByShadowAlgorithm(this.$widget, this.state.focusId, _keycode)
      if (!_focusId) _focusId = queryWidgetByAreaAlgorithm(this.$widget, this.state.focusId, _keycode)
      if (!_focusId || this.state.focusId === _focusId) return
      let _beforeFocus;
      //焦点改变之前的生命周期
      this.triggerComponentsFun(this.state.focusId, function (context) {
        if (typeof context.beforeFocusChange !== 'function') return
        _beforeFocus = context.beforeFocusChange(_focusId, _keycode)
        return _beforeFocus;
      })
      if (_beforeFocus === true) return
      if (typeof _beforeFocus === 'string') _focusId = _beforeFocus
      const _oldFocus = this.state.focusId
      this.state.focusId = _focusId;
      //焦点改变之后的生命周期
      this.$nextTick(() => {
        this.triggerComponentsFun(this.state.focusId, function (context) {
          if (typeof context.afterFocusChange === 'function') return context.afterFocusChange(_oldFocus, _keycode)
        })
      })
    },
    onKeyDown(ev) {
      //焦点移动
      if (ev.keyCode === KEYCODE.DOWN || ev.keyCode === KEYCODE.UP || ev.keyCode === KEYCODE.LEFT || ev.keyCode === KEYCODE.RIGHT) return this.onMove(ev.keyCode)
      //事件下发
      let _keyName = this.getNameByKeyCode(ev.keyCode)
      this.triggerComponentsFun(this.state.focusId, function (context) {
        if (typeof context[_keyName] === 'function') return context[_keyName](ev)
      })
    },
    //焦点修改，暴露给底层
    onChangeFocus(_newFocus) {
      this.state.focusId = _newFocus
    },
    /**
 * 从当前组件开始向上查找父组件链
 * @param {Function} callback 每找到一个符合条件的组件时执行的回调
 */
    triggerComponentsFun(widgetId, callback) {
      let current = this.$widget[widgetId].$context; // 从当前组件开始
      while (current) {
        const isTargetComponent = current.comId === this.$el.id;
        const isFocusComponent = !!this.$components[current.$el.id] || !!this.$widget[current.$el.id]
        if (isTargetComponent || isFocusComponent) {
          if (callback(current)) break;
        }
        if (isTargetComponent) break;
        current = current.$parent;
      }
    },
    getNameByKeyCode(keyCode) {
      let _name = '';
      for (const key in KEYCODE) {
        if (Object.prototype.hasOwnProperty.call(KEYCODE, key)) {
          if (KEYCODE[key] === keyCode) {
            _name = key;
            break;
          }
        }
      }
      return _name;
    },
    //内部焦点元素变化，更新焦点列表
    widgetChange(options) {
      if (!this.state.focusId) this.state.focusId = options.id;
      if (options.isdelete) { delete this.$widget[options.id]; }
      else { this.$widget[options.id] = options; }
    },
    //焦点元素内部组件变化
    otherComChange(options) {
      console.log(options, "$components");
      if (options.isdelete) { delete this.$components[options.id]; }
      else { this.$components[options.id] = options; }
    },
    //在上下文中更新本组件
    comChanges(postion = {}, isdelete = false) {
      const _info = getCommentInfo(this, { postion, isdelete })
      if (typeof this.focusFrameMethods.switchChange === 'function') {
        this.focusFrameMethods.switchChange(_info)
      } else {
        console.error('switch组件必须包裹在frame组件内')
      }
    },
  },
  watch: {

  },
};
</script>